// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// H [author] rhyme_lph
// N [email]  rhymelph@gmail.com
// j [github] https://github.com/rhymelph

import 'package:base_plugin/base_plugin.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/common/config.dart';
import 'package:finance_app/src/entities/account_entity.dart';
import 'package:finance_app/src/entities/currency_rate_entity.dart';
import 'package:finance_app/src/entities/ocr_attachment_entity.dart';
import 'package:finance_app/src/entities/payment_entity.dart';
import 'package:finance_app/src/entities/setting_data_entity.dart';
import 'package:finance_app/src/http_service/http_common_service.dart';
import 'package:finance_app/src/http_service/http_payment_service.dart';
import 'package:finance_app/src/mixin/from_attach_mixin.dart';
import 'package:finance_app/src/mixin/init_edit_data_mixin.dart';
import 'package:finance_app/src/provider/all_reports/bank_reconciliation/reconcile_account_detail_provider.dart';
import 'package:finance_app/src/provider/all_reports/bank_reconciliation/reconcile_account_record_detail_provider.dart';
import 'package:finance_app/src/provider/dashboard/bank/cash_and_bank_provider.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/utils/cash_utils.dart';
import 'package:finance_app/src/utils/date_time_utils.dart';
import 'package:finance_app/src/widgets/bottom_sheet/calendar_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/currency_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/delete_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_tip_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/list_select_bottom_sheet.dart';
import 'package:flutter/material.dart';

class NewAccountTransferProvider extends BaseProvider<PaymentEntity>
    with InitEditDataMixin<PaymentEntity>, FormAttachMixin {
  TextEditingController chequeTransactionNumberController =
      TextEditingController();
  FocusNode chequeTransactionNumberFocusNode = FocusNode();

  TextEditingController priceController = TextEditingController();
  FocusNode priceFocusNode = FocusNode();

  SettingDataCurrency unit;
  SettingDataPaymentType transactionType;

  AccountEntity fromAccount;
  TextEditingController fromPriceController = TextEditingController();
  TextEditingController toPriceController = TextEditingController();
  CurrencyRateEntity fromRate;
  AccountEntity toAccount;
  FocusNode toPriceFocusNode = FocusNode();
  FocusNode fromPriceFocusNode = FocusNode();
  CurrencyRateEntity toRate;

  int id;

  bool isEdit;

  String flowType;

  List<String> menuList = [
    // 'Edit',
    'Delete',
  ];

  bool isSelectMode;

  @override
  void dispose() {
    super.dispose();
    priceFocusNode.dispose();
    priceController.dispose();
    chequeTransactionNumberController.dispose();
    chequeTransactionNumberFocusNode.dispose();
  }

  @override
  Future get dataFuture => null;

  void unFocus() {
    chequeTransactionNumberFocusNode.unfocus();
    priceFocusNode.unfocus();
    fromPriceFocusNode.unfocus();
    toPriceFocusNode.unfocus();
  }

  void onChangeTransactionDate() {
    unFocus();
    obtainContext?.call((context) async {
      DateTime newDate = await showCalendarBottomSheet(context, date);
      if (newDate != date) {
        date = newDate;
        if (fromAccount != null && unit.key != fromAccount.currencyCode) {
          await post(
              HttpCommonService.currentRate(unit.key, fromAccount.currencyCode,
                  DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd')),
              autoHandler: AutoHandler.Toast,
              loadingTip: S.current.loading, onSuccess: (result) {
            fromRate = getEntityFromResult<CurrencyRateEntity>(result);
            fromPriceController.text = CashUtils.formatCashAmount2(num.parse(
                  priceController.text,
                ) *
                fromRate.rate);
          });
        } else if (unit.key == fromAccount?.currencyCode) {
          fromRate = CurrencyRateEntity()..rate = 1;
          fromPriceController.text = priceController.text;
        }
        if (toAccount != null && unit.key != toAccount.currencyCode) {
          await post(
              HttpCommonService.currentRate(unit.key, toAccount.currencyCode,
                  DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd')),
              autoHandler: AutoHandler.Toast,
              loadingTip: S.current.loading, onSuccess: (result) {
            toRate = getEntityFromResult<CurrencyRateEntity>(result);
            toPriceController.text = CashUtils.formatCashAmount2(num.parse(
                  priceController.text,
                ) *
                toRate.rate);
          });
        } else if (unit.key == toAccount?.currencyCode) {
          toRate = CurrencyRateEntity()..rate = 1;
          toPriceController.text = priceController.text;
        }
      }

      update();
    });
  }

  @override
  void initState() {
    super.initState();
    unit = Config.defaultCurrency;
    priceController.addListener(_handlePriceUpdate);
  }

  void onChangeUnit() async {
    unFocus();
    obtainContext?.call((context) async {
      unit = await showCurrencyBottomSheet(context, unit);
      if (fromAccount != null && unit.key != fromAccount.currencyCode) {
        await post(
            HttpCommonService.currentRate(unit.key, fromAccount.currencyCode,
                DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd')),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          fromRate = getEntityFromResult<CurrencyRateEntity>(result);
          fromPriceController.text = CashUtils.formatCashAmount2(num.parse(
                priceController.text,
              ) *
              fromRate.rate);
        });
      } else if (unit.key == fromAccount?.currencyCode) {
        fromRate = CurrencyRateEntity()..rate = 1;
        fromPriceController.text = priceController.text;
      }
      if (toAccount != null && unit.key != toAccount.currencyCode) {
        await post(
            HttpCommonService.currentRate(unit.key, toAccount.currencyCode,
                DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd')),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          toRate = getEntityFromResult<CurrencyRateEntity>(result);
          toPriceController.text = CashUtils.formatCashAmount2(num.parse(
                priceController.text,
              ) *
              toRate.rate);
        });
      } else if (unit.key == toAccount?.currencyCode) {
        toRate = CurrencyRateEntity()..rate = 1;
        toPriceController.text = priceController.text;
      }
      update();
    });
  }

  void onChangeFormAccount() {
    unFocus();
    obtainContext?.call((context) async {
      final result =
          await Routes.navigateTo(RouterGenProviders.bankAccountPage);
      if (result != null) {
        fromAccount = result;
        await post(
            HttpCommonService.currentRate(unit.key, fromAccount.currencyCode,
                DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd')),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          fromRate = getEntityFromResult<CurrencyRateEntity>(result);
          fromPriceController.text = CashUtils.formatCashAmount2(
              num.parse(priceController.text, (e) => 0.0) * fromRate.rate);
        });
        update();
      }
    });
  }

  void onChangeToAccount() {
    unFocus();
    obtainContext?.call((context) async {
      final result =
          await Routes.navigateTo(RouterGenProviders.bankAccountPage);
      if (result != null) {
        toAccount = result;
        await post(
            HttpCommonService.currentRate(unit.key, toAccount.currencyCode,
                DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd')),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          toRate = getEntityFromResult<CurrencyRateEntity>(result);
          toPriceController.text = CashUtils.formatCashAmount2(
              num.parse(priceController.text, (e) => 0.0) * toRate.rate);
        });
        update();
      }
    });
  }

  void onChangeTransactionMethod() {
    unFocus();
    obtainContext?.call((context) async {
      final result = await showPaymentMethodBottomSheet(
          context, transactionType,
          filterKey: 'payment_type.credit_card');
      if (result != null) {
        transactionType = result;
        update();
      }
    });
  }

  void onSave() async {
    unFocus();
    double total = double.parse(priceController.text, (s) => null);
    // double fromTotal = double.parse(fromPriceController.text, (e) => null);
    // double toTotal = double.parse(toPriceController.text, (e) => null);

    double fromTotal = fromRate.rate * total;
    double toTotal = toRate.rate * total;

    if (fromAccount == null) {
      showToast(S.current.please_select_from);
      return;
    }
    if (toAccount == null) {
      showToast(S.current.please_select_to);
      return;
    }
    if (transactionType == null) {
      showToast(S.current.please_select_payment_method);
      return;
    }
    PaymentEntity orderEntity;

    List<int> attachmentIds = await uploadFiles();
    if (attachmentIds == null) return;

    if (id != null) {
      await post(
          HttpPaymentService.paymentTransfer(
            account_id: fromAccount?.id,
            to_account_id: toAccount?.id,
            issued_at: DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd'),
            currency_code: unit?.key,
            total: fromTotal,
            to_total: toTotal,
            payment_type_id: transactionType?.id,
            attachment_ids: attachmentIds,
          ),
          autoHandler: AutoHandler.Toast,
          loadingTip: S.current.loading, onSuccess: (result) {
        orderEntity = getEntityFromResult<PaymentEntity>(result);
      });
    } else {
      await post(
          HttpPaymentService.paymentTransfer(
            account_id: fromAccount?.id,
            to_account_id: toAccount?.id,
            issued_at: DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd'),
            currency_code: unit?.key,
            total: fromTotal,
            to_total: toTotal,
            payment_type_id: transactionType?.id,
          ),
          autoHandler: AutoHandler.Toast,
          loadingTip: S.current.loading, onSuccess: (result) {
        orderEntity = getEntityFromResult<PaymentEntity>(result);
      });
    }
    if (orderEntity != null) {
      Providers.get<CashAndBankProvider>(
              RouterGenProviders.cashAndBankPage, null)
          ?.onRefresh();
      Providers.get<ReconcileAccountDetailProvider>(
              RouterGenProviders.reconcileAccountDetailPage, null)
          ?.onRequestRefresh();
      Providers.get<ReconcileAccountRecordDetailProvider>(
              RouterGenProviders.reconcileAccountRecordDetailPage, null)
          ?.onRequestRefresh();
      if (isSelectMode == true) {
        obtainContext?.call((context) {
          Navigator.of(context).pop();
        });
      } else {
        id = orderEntity.id;
        isEdit = false;
        update();
      }
    }
  }

  void initData(PaymentEntity data) {
    if (data == null) return;
    this.id = data.id;
    flowType = data.flowType;
    isEdit = false;
    date = DateTimeUtils.toDateTime(data.issuedAt);
    chequeTransactionNumberController.text = data.chequeNumber;
    priceController.text = data.total?.toString();
    fromPriceController.text = data.total?.toString();
    toPriceController.text = data.relatedPayment.total?.toString();
    // toPriceController.text = data.total?.toString();
    fromAccount = data.account;
    toAccount = data.toAccount;
    unit = Config.settingData.currency.firstWhere(
        (element) => element.key == data.currencyCode,
        orElse: () => null);
    if (data.paymentTypeId != null) {
      transactionType = Config.settingData.paymentType.firstWhere(
          (element) => element.id == data.paymentTypeId,
          orElse: () => null);
    }
  }

  void onSelectMenu(String value) {
    switch (value) {
      case 'Edit':
        onChangeEditMode();
        break;
      case 'Delete':
        onDelete();
        break;
    }
  }

  void onChangeEditMode() {
    isEdit = !isEdit;
    update();
  }

  void onDelete() async {
    obtainContext?.call((context) async {
      bool isSuccess = await showDeleteTransactionInfoBottomSheet(context);
      if (isSuccess == true) {
        isSuccess = false;
        await post(HttpPaymentService.deletePayment(id),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          isSuccess = true;
        });
        if (isSuccess == true) {
          await showDeleteSuccessTipBottomSheet(context);
          obtainContext?.call((context) {
            Navigator.of(context).pop({
              'delete': true,
            });
          });
        }
      }
    });
  }

  void _handlePriceUpdate() {
    update();
    String price = priceController.text;
    if (price.isEmpty) {
      price = '0.00';
    }
    if (fromRate != null) {
      if (unit?.key != fromAccount?.currencyCode) {
        fromPriceController.text =
            CashUtils.formatCashAmount2(num.parse(price) * fromRate.rate);
      } else {
        fromPriceController.text = price;
      }
    }
    if (toRate != null) {
      if (unit?.key != toAccount?.currencyCode) {
        toPriceController.text =
            CashUtils.formatCashAmount2(num.parse(price) * toRate.rate);
      } else {
        toPriceController.text = price;
      }
    }
  }

  @override
  Future get editDataFuture => null;

  @override
  TextEditingController get numberCtl => null;

  @override
  String get type => 'transfer';

  @override
  List<OcrAttachmentEntity> get attachments => data?.attachments;
}
